
#include "mapStreet.hpp"
#include "../config/config.hpp"
#include <math.h>

#define POW2(x){x*x}

MapStreet::MapStreet(Edge *e, Graph *g)
{
	this->edge = e;
	this->setId(this->edge->getId());
	this->setMapElementType(STREET);
	
	Node *nodeTemp = NULL;
	
	nodeTemp = g->getNode(this->edge->getOriginId());
	this->setIntersectionOriginPositionX(nodeTemp->getPositionX());
	this->setIntersectionOriginPositionY(nodeTemp->getPositionY());
	this->setPositionX(nodeTemp->getPositionX());
	this->setPositionY(nodeTemp->getPositionY());
	
	nodeTemp = g->getNode(this->edge->getDestinyId());
	this->setIntersectionDestinyPositionX(nodeTemp->getPositionX());
	this->setIntersectionDestinyPositionY(nodeTemp->getPositionY());

	int xOPos = this->getIntersectionOriginPositionX();
	int yOPos = this->getIntersectionOriginPositionY();
	int xDPos = this->getIntersectionDestinyPositionX();
	int yDPos = this->getIntersectionDestinyPositionY();

	int width = xOPos - xDPos;
	if(width < 0)
		width*= (-1);

	int height = yOPos - yDPos;
	if(height < 0)
		height*= (-1);

	std::string source;
	RoadType type = this->edge->getRoadType();
	switch(type){
		case CALLE:
			source = Config::get("street_image_source");
			break;

		case AVENIDA:
			source = Config::get("avenue_image_source");
			break;

		case AUTOPISTA:
			source = Config::get("highway_image_source");
			break;

		default:
			source = Config::get("street_image_source");

	}

    this->setImageSource(source);
	this->setImageWidth(width);
	this->setImageHeight(height);
	
	this->inclination = atan2((double)(xOPos - xDPos),(double)(yOPos - yDPos));
	this->setDirection();

	nodeTemp = NULL;
}

MapStreet::MapStreet(std::string id)
{
	this->setId(id);
	this->setMapElementType(STREET);
}

std::string MapStreet::getIntersectionOriginId()
{
	return this->edge->getOriginId();
}

std::string MapStreet::getIntersectionDestinyId()
{
	return this->edge->getDestinyId();
}

std::string MapStreet::getStreetName()
{
	return this->edge->getRoadName();
}

float MapStreet::getMaxVelocity()
{
	return this->edge->getWeight().getVelocity();
}

int MapStreet::getIntersectionOriginPositionX()
{
	return this->nodeOriginPositionX;
}

int MapStreet::getIntersectionOriginPositionY()
{
	return this->nodeOriginPositionY;
}

int MapStreet::getIntersectionDestinyPositionX()
{
	return this->nodeDestinyPositionX;
}

int MapStreet::getIntersectionDestinyPositionY()
{
	return this->nodeDestinyPositionY;
}

void MapStreet::setIntersectionOriginPositionX(int x)
{
	this->nodeOriginPositionX = x;
}

void MapStreet::setIntersectionOriginPositionY(int y)
{
	this->nodeOriginPositionY = y;
}

void MapStreet::setIntersectionDestinyPositionX(int x)
{
	this->nodeDestinyPositionX = x;
}

void MapStreet::setIntersectionDestinyPositionY(int y)
{
	this->nodeDestinyPositionY = y;
}

double MapStreet::getInclination()
{
	return this->inclination;
}

int MapStreet::getInitialHeight()
{
	return this->edge->getInitialHeight();
}

int MapStreet::getFinalHeight()
{
	return this->edge->getFinalHeight();
}

bool MapStreet::heightIncrease()
{
	return ((this->getFinalHeight() - this->getInitialHeight()) > 0);
}

int MapStreet::getHeightModule()
{
	return (this->getFinalHeight() - this->getInitialHeight() > 0)? (this->getFinalHeight() - this->getInitialHeight()) : (this->getFinalHeight() - this->getInitialHeight()) * -1;
}

int MapStreet::getInitialMPHeight()
{
	return this->edge->getInitialMPHeight();
}

int MapStreet::getFinalMPHeight()
{
	return this->edge->getFinalMPHeight();
}

bool MapStreet::belongToMP()
{
	return this->edge->getBelongToMP();
}

RoadType MapStreet::getRoadType()
{
	return this->edge->getRoadType();
}

int MapStreet::getStreetModule()
{
	int originPosX = this->getIntersectionOriginPositionX();
	int originPosY = this->getIntersectionOriginPositionY();
	int destinyPosX = this->getIntersectionDestinyPositionX();
	int destinyPosY = this->getIntersectionDestinyPositionY();
	int pow1 = POW2((originPosX-destinyPosX));
	int pow2 = POW2((originPosY-destinyPosY));
	int sumpows = pow1 + pow2;
	int module = (int) sqrt((double)sumpows);
	
	return module;
}

bool MapStreet::isInHeightRange(int h)
{
	if(this->getInitialHeight() < this->getFinalHeight())
		return (this->getInitialHeight() <= h && h <= this->getFinalHeight());
	
	return (this->getInitialHeight() >= h && h >= this->getFinalHeight());
}

int MapStreet::getHeightPositionX(int h)
{
	int module = this->getStreetModule();
	int iniEdgeHeight = this->getInitialHeight();
	int finEdgeHeight = this->getFinalHeight();
	int heightModule = this->getHeightModule();

	int positionX = 0;
	double percent = 0;

	if(this->getIntersectionOriginPositionY() == this->getIntersectionDestinyPositionY())
	{
		int hdif = h - this->getInitialHeight();
		hdif = (hdif < 0)? -hdif : hdif;
		percent = (double) hdif / heightModule;
	}

	positionX = module*percent;
	BifurcationOption dir = this->getDirection();
	if((dir == DOWN)||(dir == RIGHT))
		return this->getIntersectionOriginPositionX() + positionX;
	else
		return this->getIntersectionOriginPositionX() - positionX;
}

int MapStreet::getHeightPositionY(int h)
{
	int module = this->getStreetModule();
	int iniEdgeHeight = this->getInitialHeight();
	int finEdgeHeight = this->getFinalHeight();
	int heightModule = this->getHeightModule();

	int positionY = 0;
	double percent = 0;

	if(this->getIntersectionOriginPositionX() == this->getIntersectionDestinyPositionX())
	{
		int hdif = h - this->getInitialHeight();
		hdif = (hdif < 0)? -hdif : hdif;
		percent = (double) hdif / heightModule;
	}

	positionY = module*percent;
	BifurcationOption dir = this->getDirection();
	if((dir == DOWN)||(dir == RIGHT))
		return this->getIntersectionOriginPositionY() + positionY;
	else
		return this->getIntersectionOriginPositionY() - positionY;
}

void MapStreet::setDirection()
{
	int originPosX = this->getIntersectionOriginPositionX();
	int originPosY = this->getIntersectionOriginPositionY();
	int destinyPosX = this->getIntersectionDestinyPositionX();
	int destinyPosY = this->getIntersectionDestinyPositionY();
	BifurcationOption result = LEFT;

	//Eje vertical
	if(originPosY == destinyPosY)
	{
		   if(originPosX > destinyPosX)
				   result = LEFT;
		   else
				   result = RIGHT;
	}
	else if(originPosX == destinyPosX)
	{
		   if(originPosY > destinyPosY)
				   result = UP;
		   else
				   result = DOWN;
	}

	this->direction = result;
}

BifurcationOption MapStreet::getDirection()
{
	return this->direction;
}

std::string MapStreet::getDirectionString()
{
	int dir = (int) this->getDirection();
	std::string result;
	switch(dir)
	{
		case 0:  
			result = "LEFT";
			break;
		case 1:  
			result = "RIGHT";
			break;
		case 2:  
			result = "UP";
			break;
		case 3:  
			result = "DOWN";
			break;
		default:
			result = "LEFT";
	}
	return result;
}

int MapStreet::getStreetHeightByPosition(int x, int y, bool onCorrectDirection, int xDisp, int yDisp)
{
	int originPosX = this->getIntersectionOriginPositionX() + xDisp;
	int originPosY = this->getIntersectionOriginPositionY() + yDisp;
	int streetModule = this->getStreetModule();
	int heightModule = this->getHeightModule();
	BifurcationOption dir = this->getDirection();
	bool increase = this->heightIncrease();
	int posModule = 0;
	int height = 0;

	double percent = 0;

	int xdif = originPosX - x;
		xdif = (xdif < 0)? -xdif : xdif;

	int ydif = originPosY - y;
		ydif = (ydif < 0)? -ydif : ydif;

	//Eje vertical
	if((dir == DOWN)||(dir == UP))
		percent = (double) ydif / streetModule;
	//Eje horizontal
	else if((dir == LEFT)||(dir == RIGHT))
		percent = (double) xdif / streetModule;

	posModule = heightModule * percent;
	//if(((increase)&&(dir == LEFT))||((increase)&&(dir == DOWN)))
	//	height = this->getInitialHeight() + posModule;
	//else if((!increase)&&(dir == RIGHT)||((!increase)&&(dir == UP)))
	//	height = this->getInitialHeight() - posModule;
	//else if(((!increase)&&(dir == LEFT))||((!increase)&&(dir == DOWN)))
	//	height = this->getFinalHeight() - posModule;
	//else if((increase)&&(dir == RIGHT)||((increase)&&(dir == UP)))
	//	height = this->getInitialHeight() + posModule;
	
	if(increase)
		height = this->getInitialHeight() + posModule;
	else
		height = this->getInitialHeight() - posModule;

	return height;
}

int MapStreet::getLongitude()
{
	return (int) this->edge->getWeight().getLength();
}